<?php
/**
 * Description:
 * Author: hezhizheng
 * Date: 2018/11/14
 * Time: 14:21
 * Created by Created by Panxsoft.
 */

namespace App\Models\Traits;

use App\Models\Categories\Category;
use App\Models\Products\Product;
use App\Models\Products\ProductAttribute;
use App\Models\Products\ProductDescription;
use App\Models\Products\ProductOption;
use App\Models\Products\ProductOptionValue;
use App\Services\MobileApp\AppEnv;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

/**
 * @method self filterCategoryId(?int $category_id)
 * @method self filterStockStatus(?int $stock_status_id)
 * @method self filterManufacturers(?array $manufacturer_ids)
 * @method self filterOptions(?array $option_ids)
 * @method self filterOptionValues(?array $option_value_ids)
 * @method self filterAttributes(?array $attributes)
 * @method self filterKeyword(?string $keyword)
 * @method self searchKeyword(?string $keyword)
 * @method static self filterPriceRange(?array $price_range)
 * @method static self filterOrderBy($sort_column)
 * @method self filterOnShelf()
 *
 * 不要使用 @ mixin Product Product类出现属性 / 方法的递归显示
 */
trait ProductFilter
{
    /**
     * @used-by filterCategoryId
     * @param Builder $query
     * @param $category_id
     */
    public function scopeFilterCategoryId(Builder $query, ?int $category_id)
    {
        if ($category_id) {

            $category_ids = Category::getSubCategoryIds([$category_id]);

            $query->whereHas('productToCategories', function(Builder $query) use($category_ids){
                return $query->whereIn('category_id', $category_ids);
            });
        };
    }

    /**
     * @used-by filterStockStatus
     * @param Builder $query
     * @param $stock_status_id
     */
    public function scopeFilterStockStatus(Builder $query, ?int $stock_status_id)
    {
        if ($stock_status_id) {
            $query->where('stock_status_id', $stock_status_id);
        };
    }

    /**
     * @used-by filterManufacturers
     *
     * @param Builder $query
     * @param $manufacturer_ids
     *
     * @return Builder
     */
    public function scopeFilterManufacturers(Builder $query, ?array $manufacturer_ids)
    {
        if ($manufacturer_ids) {
            return $query->whereIn('manufacturer_id', $manufacturer_ids);
        } else {
            return $query;
        };
    }

    /**
     * @used-by filterAttributes
     *
     * @param Builder $query
     * @param $attributes
     *
     * @return Builder
     */
    public function scopeFilterAttributes(Builder $query, ?array $attributes)
    {
        if (!$attributes) return $query;

        /** @var Collection $product_attributes */
        $product_attributes = (new ProductAttribute)
            ->where('language_id', AppEnv::languageId())
            ->whereIn('attribute_id', array_column($attributes, 'attribute_id'))
            ->whereIn('text', array_column($attributes, 'text'))
            ->get();

        $product_ids = $product_attributes->pluck('product_id')->all();

        foreach($attributes as $attribute)
        {
            $attribute_product_ids = $product_attributes->where('attribute_id', $attribute['attribute_id'])
                ->where('text', $attribute['text'])
                ->pluck('product_id')
                ->all();

            $product_ids = array_intersect($attribute_product_ids, $product_ids);
        }


        return $query->whereIn('product_id', $product_ids);
    }

    /**
     * @deprecated - 搜索不需要过滤选项
     *
     * @used-by filterOptions
     *
     * @param Builder $query
     * @param $option_ids
     */
    public function scopeFilterOptions(Builder $query, ?array $option_ids)
    {
        if ($option_ids) {
            $product_ids = (new ProductOption)
                ->whereIn('option_id', $option_ids)
                ->pluck('product_id');

            $query->whereIn('product_id', $product_ids);
        }
    }

    /**
     * @used-by filterOptionValues
     *
     * @param Builder $query
     * @param $option_value_ids
     */
    public function scopeFilterOptionValues(Builder $query, ?array $option_value_ids)
    {
        if ($option_value_ids) {
            $product_ids = (new ProductOptionValue)
                ->whereIn('option_value_id', $option_value_ids)
                ->pluck('product_id')
                ->unique();

            $query->whereIn('product_id', $product_ids);
        }
    }

    /**
     * @used-by filterKeyword
     * @param Builder $query
     * @param $keyword
     * @return Builder
     */
    public function scopeFilterKeyword(Builder $query, ?string $keyword)
    {
        if (!$keyword) return $query;

        return $query->whereIn('product_id', ProductDescription::getProductIdsByKeyword($keyword));
    }

    /**
     * @used-by searchKeyword
     * @param Builder $query
     * @param $keyword
     * @return Builder
     */
    public function scopeSearchKeyword(Builder $query, ?string $keyword)
    {
        if (! $keyword) return $query;

        $product_ids_filter_by_description = (ProductDescription::trySearchProductIds($keyword)) ?? [];
        $product_ids_filter_by_product = (Product::trySearchProductIds($keyword)) ?? [];

        $product_ids = array_merge($product_ids_filter_by_description, $product_ids_filter_by_product);

        return $query->whereIn('product_id', $product_ids);
    }

    /**
     * @used-by filterOnShelf
     * @param Builder $query
     * @return Builder
     */
    public function scopeFilterOnShelf(Builder $query)
    {
        return $query->where('status', Product::PRODUCT_STATUS_ON)
            ->where('date_available', '<=', now()->toDateString())
            ->whereHas('productToStore', function(Builder $query) {
                return $query->where('store_id', AppEnv::storeId());
            });
    }

    /**
     * @used-by filterPriceRange
     * @param Builder $query
     * @param array $price_range
     * @return Builder
     */
    public function scopeFilterPriceRange(Builder $query, ?array $price_range)
    {
        if (!$price_range) return $query;

        $customer_group_id = AppEnv::customerGroupId();
        $actual_price_select = DB::raw(sprintf(Product::ACTUAL_PRICE_SQL, $customer_group_id, $customer_group_id));

        return $query->addSelect($actual_price_select)
            ->having('actual_price', '>=', $price_range[0])
            ->having('actual_price', '<=', $price_range[1]);

    }

    /**
     * @used-by filterOrderBy()
     *
     * @param Builder $query
     * @param $sort_column
     * @return Builder
     */
    public function scopeFilterOrderBy(Builder $query, $sort_column)
    {
        // 排序条件：date_added, sales_volume, actual_price, review
        $sort_column = $sort_column ?? 'date_added';
        $select = [];

        if ($sort_column === 'actual_price') {
            $customer_group_id = AppEnv::customerGroupId();
            $select = DB::raw(sprintf(Product::ACTUAL_PRICE_SQL, $customer_group_id, $customer_group_id));

        } else if ($sort_column === 'sales_volume') {

            $select = DB::raw(Product::SALES_VOLUME_SQL);

        } else if ($sort_column === 'review') {

            $select = DB::raw(Product::REVIEW_SQL);
        }

        return $query->addSelect($select);
    }

}